package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"strconv"

	log "github.com/sirupsen/logrus"
	"github.com/spf13/pflag"
)

type T6006GPS struct {
	Latitude  string `json:"latitude"`
	Longitude string `json:"longitude"`
	Province  string `json:"province"`
	TrueTrack string `json:"true_track"`
	SpeedKmh  string `json:"speed_kmh"`
}

type T6006 struct {
	ISP     string   `json:"isp"`
	Signal  int      `json:"signal"`
	Service string   `json:"service"`
	Yaw     string   `json:"yaw"`
	Time    string   `json:"time"`
	Depth   string   `json:"depth"`
	Mac     string   `json:"mac"`
	Pitch   string   `json:"pitch"`
	Roll    string   `json:"roll"`
	GPS     T6006GPS `json:"gps"`
	JSON    string   `json:"json"`
}

func main() {
	cfgFile := pflag.StringP("config", "c", "", "")
	pflag.Parse()
	if *cfgFile == "" {
		fmt.Printf("must provide config file")
		os.Exit(-1)
	}
	config, err := loadConfig(*cfgFile)
	if err != nil {
		panic(err)
	}
	ch, err := NewMQTT(config.MQTTConfig)
	if err != nil {
		log.WithFields(log.Fields{"err": err}).Fatal("failed connect to mqtt")
	}
	cache, err := NewCache(config.CacheConfig)
	if err != nil {
		log.WithFields(log.Fields{"err": err}).Fatal("failed connect to cache")
	}
	for msg := range ch {
		payload := msg.Payload()
		var data T6006
		err := json.Unmarshal(payload, &data)
		if err != nil {
			log.WithFields(log.Fields{
				"err":       err,
				"payload":   payload,
				"qos":       msg.Qos(),
				"topic":     msg.Topic(),
				"MessageID": msg.MessageID(),
			}).Error("failed parse received message")
			break
		}
		mac := data.Mac
		key, err := encodeMac(mac)
		if err != nil {
			log.WithFields(log.Fields{"err": err, "mac": mac}).Error("error format mac")
			break
		}
		values := formatValues(data)
		err = cache.Set(key, values)
		if err != nil {
			log.WithFields(log.Fields{"err": err, "data": data, "key": key}).Error("failed set cache")
		}
	}
}

func loadConfig(path string) (Config, error) {
	f, err := os.Open(path)
	if err != nil {
		return Config{}, err
	}
	defer f.Close() // nolint
	content, err := ioutil.ReadAll(f)
	if err != nil {
		return Config{}, err
	}
	var config Config
	err = json.Unmarshal(content, &config)
	return config, err
}

func encodeMac(mac string) (string, error) {
	mac = strings.Replace(mac, ":", "", -1)
	mac = strings.ToUpper(mac)
	return mac, nil
}

func formatValues(data T6006) map[string]interface{} {
	m := map[string]interface{}{}
	m["isp"] = data.ISP
	m["signal"] = data.Signal
	m["service"] = data.Service
	m["yaw"], _ = strconv.ParseFloat(data.Yaw, 64)
	m["time"] = data.Time
	m["depth"], _ = strconv.ParseFloat(data.Depth, 64)
	m["mac"] = data.Mac
	m["pitch"], _ = strconv.ParseFloat(data.Pitch, 64)
	m["roll"], _ = strconv.ParseFloat(data.Roll, 64)
	m["longitude"], _ = strconv.ParseFloat(data.GPS.Longitude, 64)
	m["latitude"], _ = strconv.ParseFloat(data.GPS.Latitude, 64)
	m["province"] = data.GPS.Province
	m["true_track"], _ = strconv.ParseFloat(data.GPS.TrueTrack, 64)
	m["speed_kmh"], _ = strconv.ParseFloat(data.GPS.SpeedKmh, 64)
	return m
}